/**
 * Copyright (c) Huawei Technologies Co., Ltd. 1987-2021. All rights reserved.
*/

package com.gitee.fufu669.utils;

import com.gitee.fufu669.aspect.Logging;
import com.gitee.fufu669.utils.CacheHttpUtil;
import com.gitee.fufu669.utils.CacheJsonUtil;
import com.gitee.fufu669.utils.CachePasswordUtil;
import com.gitee.fufu669.utils.vo.SwaggerApiDocsVo;
import com.gitee.fufu669.utils.vo.SwaggerApiDocsVo.Tag;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

//把swagger转成wiki
/**
 * 把swagger转成wiki
*/
public class CacheSwaggerToHtmlUtil implements Logging {
    //日志对象
    /**
     * 日志对象
    */
    public static final Logger logger = LoggerFactory.getLogger(CacheSwaggerToHtmlUtil.class);

    //赋值
    /**
     * 赋值
    */
    public static void info(@ApiParam("serverUrl，比如你的swagger地址是http://192.168.22.183:5000/swagger-ui.html，那么这里就填入http://192.168.22.183:5000") @RequestParam(value = "serverUrl", required = false, defaultValue = "http://localhost:10666") String serverUrl, @ApiParam("showServerUrl，用来展示在wiki中的服务器的路径，比如http://www.test.com") @RequestParam(value = "showServerUrl", required = false, defaultValue = "http://localhost:10666") String showServerUrl, HttpServletRequest request, HttpServletResponse response) {
        //赋值
        String swaggerUrl = serverUrl + "/v2/api-docs";
        //把swagger转成wiki
        getSwagger(swaggerUrl, showServerUrl, request, response);
    }

    //把swagger转成wiki
    /**
     * 把swagger转成wiki
    */
    public static void getSwagger(String swaggerUrl, String showServerUrl, HttpServletRequest request, HttpServletResponse response) {
        //字符串赋值
        String swaggerString = CacheHttpUtil.getJson(swaggerUrl);
        //判断
        if (!StringUtils.isEmpty(swaggerString)) {
            //替换
            swaggerString = swaggerString.replaceAll("\\$ref", "ref");
            //拿swagger主对象
            SwaggerApiDocsVo swaggerApiDocsVo = (SwaggerApiDocsVo) CacheJsonUtil.toObject(swaggerString, SwaggerApiDocsVo.class);
            //尝试下面的代码
            try {
                //字符串赋值
                String topTitle = swaggerApiDocsVo.getInfo().getTitle();
                //尝试下面的代码
                try {
                    //设置返回编码
                    response.setCharacterEncoding("utf-8");
                    //设置下载
                    response.setContentType("application/x-download");
                    //设置下载文件名
                    response.setHeader("Content-Disposition", "attachment;filename=Api_Document_v" + CachePasswordUtil.generateTokenNumberMilliSeconds() + ".html");
                    //增加
                    response.addHeader("Pargam", "no-cache");
                    //增加
                    response.addHeader("Cache-Control", "no-cache");
                    //捕捉异常
                } catch (Exception e) {
                    //打印异常
                    e.printStackTrace();
                }

                //拿输出流
                OutputStream outputStream = response.getOutputStream();
                //写加粗文字
                writeBoldText(outputStream, topTitle, 36);
                //字符串赋值
                String topDescription = swaggerApiDocsVo.getInfo().getDescription();
                //写加粗文字
                writeBoldText(outputStream, "1.0 "+topDescription, 26);
                //拿许可
                Map<String, Object> mapLicense = swaggerApiDocsVo.getInfo().getLicense();
                //拿定义
                Map<String, Object> definitions = swaggerApiDocsVo.getDefinitions();
                //写文字
                writeText(outputStream, "协议: " + mapLicense.get("name") + " " + mapLicense.get("url"), 6);
                //写文字
                writeText(outputStream, "版本: " + swaggerApiDocsVo.getInfo().getVersion(), 6);
                //写文字
                writeText(outputStream, "服务需知: " + swaggerApiDocsVo.getInfo().getTermsOfService(), 6);
                // 赋值
                Integer index = 1;
                //拿迭代器
                Iterator var26 = swaggerApiDocsVo.getTags().iterator();

                //循环
                while (var26.hasNext()) {
                    //拿下一个标签
                    Tag tag = (Tag) var26.next();
                    //判断
                    if("swagger-to-wiki-controller".equals(tag.getName())){
                        //继续
                        continue;
                    }
                    //赋值
                    index = index + 1;
                    //写文字
                    writeText(outputStream, "", 6);
                    //写加粗文字
                    writeBoldText(outputStream, index + ".0 接口大类: " + tag.getDescription(), 26);
                    //写文字
                    writeText(outputStream, "", 6);
                    //写加粗文字
                    writeBoldText(outputStream, "代码类名: " + tag.getName(), 16);
                    //赋值
                    Integer subIndex = 0;
                    //拿迭代器
                    Iterator var29 = swaggerApiDocsVo.getPaths().entrySet().iterator();
                    //循环
                    while (var29.hasNext()) {
                        //拿下一个
                        Entry<String, Object> entry = (Entry) var29.next();
                        //拿值
                        Map<String, Object> getPostValue = (Map) entry.getValue();
                        //拿迭代器
                        Iterator var32 = getPostValue.entrySet().iterator();

                        //循环
                        while (var32.hasNext()) {
                            //拿下一个
                            Entry<String, Object> entryGetPostValue = (Entry) var32.next();
                            //拿值
                            Map<String, Object> getPostValueDetail = (Map) entryGetPostValue.getValue();
                            //拿出
                            List<String> tags = (List) getPostValueDetail.get("tags");
                            //判断
                            if (tags.contains(tag.getName())) {
                                //赋值
                                subIndex = subIndex + 1;
                                //写文字
                                writeText(outputStream, "", 6);
                                //拿出
                                writeBoldText(outputStream, index + "." + subIndex + " 接口描述: " + getPostValueDetail.get("summary"), 16);
                                //写文字
                                writeText(outputStream, "", 6);
                                //写加粗文字
                                writeText(outputStream, "接口路径: " + (StringUtils.isEmpty(showServerUrl) ? "http://" + swaggerApiDocsVo.getHost() : showServerUrl) + notNull( entry.getKey()), 6);
                                //写文字
                                writeText(outputStream, "方法类型: " + notNull( entryGetPostValue.getKey()), 6);
                                //拿出
                                writeText(outputStream, "消费类型: " + CacheJsonUtil.toJson(getPostValueDetail.get("consumes")), 6);
                                //拿出
                                writeText(outputStream, "生产类型: " + CacheJsonUtil.toJson(getPostValueDetail.get("produces")), 6);
                                //写文字
                                writeText(outputStream, "", 6);
                                //写入参
                                writeParams(outputStream, getPostValueDetail);
                                //写文字
                                writeText(outputStream, "", 6);
                                //写文字
                                writeText(outputStream, "", 6);
                                //写加粗文字
                                writeBoldText(outputStream, "出参: ", 16);
                                //写文字
                                writeText(outputStream, "", 6);
                                //拿出
                                Map<String, Object> responseMap = (Map) getPostValueDetail.get("responses");
                                //写回应详情
                                writeResponseDetail(outputStream, responseMap, definitions);
                                //写文字
                                writeText(outputStream, "", 6);
                            }
                        }
                    }
                }
                //增加
                index +=1;
                //写所有对象定义
                writeAllDefinitions(outputStream, definitions, index);
                //清空内存的缓冲区数据
                outputStream.flush();
                //关闭
                outputStream.close();
                //捕捉异常
            } catch (Exception e) {
                // 打印异常
                e.printStackTrace();
            }

        }
    }

    //写所有定义
    /**
     * 写所有定义
    */
    public static void writeAllDefinitions(OutputStream outputStream, Map<String, Object> definitions, Integer index) {
        //写文字
        writeText(outputStream, "", 6);
        //写加粗文字
        writeBoldText(outputStream, index+".0 所有对象的定义", 26);
        //判断是否非空
        if (definitions != null) {
            //赋值
            int subIndex = 1;
            //拿迭代器
            Iterator var3 = definitions.entrySet().iterator();

            //循环
            while (var3.hasNext()) {
                //拿下一个
                Entry<String, Object> entry = (Entry) var3.next();
                //写文字
                writeText(outputStream, "", 6);
                //写加粗文字
                writeBoldText(outputStream, "对象定义" + subIndex + " " + notNull( entry.getKey()), 7);
                //写定义
                writeDefinitions(outputStream, (Map) entry.getValue());
                //加1
                ++subIndex;
            }
            //写文字
            writeText(outputStream, "", 6);
        }
    }

    //写入参
    /**
     * 写入参
    */
    public static void writeParams(OutputStream outputStream, Map getPostValueDetail) {
        //拿出
        List<Map> parameters = (List) getPostValueDetail.get("parameters");
        //判断是否非空
        if (parameters != null) {
            //写加粗文字
            writeBoldText(outputStream, "入参: ", 16);
            //赋值
            int i = 1;
            //尝试下面的代码
            try {
                //写入
                outputStream.write(("<table style='border:1px dash solid'><tr>" +
                        " <td style='border-top:1px dash solid' ><span style='font-size:6'>参数名称</span></td>" +
                        " <td style='border-top:1px dash solid' ><span style='font-size:6'>参数位置</span></td> <td style='border-top:1px dash solid' >参数类型type</td>" +
                        " <td style='border-top:1px dash solid' ><span style='font-size:6'>参数描述</span></td>" +
                        " <td style='border-top:1px dash solid' ><span style='font-size:6'>参数引用</span></td>" +
                        // TODO
                        "</tr>").getBytes(StandardCharsets.UTF_8));
                //遍历
                for (Iterator var7 = parameters.iterator(); var7.hasNext(); ++i) {
                    //拿下一个
                    Map parameter = (Map) var7.next();
                    //字符串赋值
                    String type = notNull( parameter.get("type"));
                    //赋值
                    String ref = "";
                    //判断是否是空
                    if (StringUtils.isEmpty(type)) {
                        //拿出
                        Map schema = (Map) parameter.get("schema");
                        //转换成json字符串
                        type = CacheJsonUtil.toJson(schema);
                        //判断是否非空
                        if (schema.get("ref") != null) {
                            //拿出
                            ref = notNull( schema.get("ref"));
                            //赋值
                            type = notNull( schema.get("type"));
                            //替换
                            ref = ref.replaceAll("#/definitions/", "");
                        // 否则
                        }else{
                            //拿出
                            Map items = (Map)schema.get("items");
                            //判断是否非空
                            if(items!=null){
                                //赋值
                                type = notNull( schema.get("type"));
                                //拿出
                                ref = notNull( items.get("ref"));
                                //替换
                                ref = ref.replaceAll("#/definitions/", "");
                            }
                        }
                        //判断
                    } else if (parameter.get("items") != null) {
                        //拿出
                        type = type + " " + CacheJsonUtil.toJson(parameter.get("items"));
                    }
                    //写入
                    outputStream.write(("<tr>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( parameter.get("name")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( parameter.get("in"))  + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( type)  + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( parameter.get("description"))  + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( ref ) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write(("</tr>").getBytes(StandardCharsets.UTF_8));
                }
                //写入
                outputStream.write(("</table>").getBytes(StandardCharsets.UTF_8));
                //捕捉异常
            } catch (Exception e) {
                //打印异常
                e.printStackTrace();
            }
        }

    }

    //写回应详情
    /**
     * 写回应详情
    */
    public static void writeResponseDetail(OutputStream outputStream, Map<String, Object> responseMap, Map<String, Object> definitions) {
        //拿出
        Map<String, Object> descriptionSchemeMap = (Map) responseMap.get("200");
        //判断是否非空
        if (descriptionSchemeMap.get("schema") != null) {
            //拿出
            Map<String, Object> schema = (Map) descriptionSchemeMap.get("schema");
            //判断是否非空
            if (schema.get("ref") != null) {
                //赋值
                String schemaString = "" + schema.get("ref");
                //替换
                schemaString = schemaString.replaceAll("#/definitions/", "");
                //拿出
                Map<String, Object> schemaDefinitions = (Map) definitions.get(schemaString);
                //写加粗文字
                writeBoldText(outputStream, schemaString, 7);
                //写定义
                writeDefinitions(outputStream, schemaDefinitions);
                //否则
            } else {
                //写文字
                writeText(outputStream, CacheJsonUtil.toJson(schema), 6);
            }
        }

    }

    //写定义
    /**
     * 写定义
    */
    public static void writeDefinitions(OutputStream outputStream, Map<String, Object> schemaDefinitions) {
        //判断是否非空
        if (schemaDefinitions != null) {
            //定义
            Map properties;
            //定义
            Iterator var4;
            //定义
            Entry propertiesEntry;
            //判断是否非空
            if (schemaDefinitions.get("properties") != null) {
                //拿出
                properties = (Map) schemaDefinitions.get("properties");
                //赋值
                int i = 1;
                //尝试下面的代码
                try {
                    //写入
                    outputStream.write(("<table style='border:1px dash solid'><tr>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>名称</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>类型</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>格式</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>样例</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>说明</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>引用见《所有对象的定义》</span></td>" +
                            // TODO
                            "</tr>").getBytes(StandardCharsets.UTF_8));
                    //遍历
                    for (Iterator var8 = properties.entrySet().iterator(); var8.hasNext(); ++i) {
                        //拿下一个
                        propertiesEntry = (Entry) var8.next();
                        //拿值
                        Map<String, Object> propertiesEntryValueMap = (Map) propertiesEntry.getValue();
                        //写入
                        outputStream.write(("<tr>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( propertiesEntry.getKey()) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( propertiesEntryValueMap.get("type")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( propertiesEntryValueMap.get("format")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( propertiesEntryValueMap.get("example")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( propertiesEntryValueMap.get("description")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( getRefString(propertiesEntryValueMap)) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                        //写入
                        outputStream.write(("</tr>").getBytes(StandardCharsets.UTF_8));
                    }
                    //写入
                    outputStream.write(("</table>").getBytes(StandardCharsets.UTF_8));
                    //捕捉异常
                } catch (Exception e) {
                    //打印异常
                    e.printStackTrace();
                }
                //判断
            } else if (schemaDefinitions.get("additionalProperties") != null) {
                //拿出
                properties = (Map) schemaDefinitions.get("additionalProperties");
                //赋值
                int rows = 0;
                //遍历
                for (var4 = properties.entrySet().iterator(); var4.hasNext(); ++rows) {
                    //拿下一个
                    propertiesEntry = (Entry) var4.next();
                }
                //赋值
                int i = 1;
                //字符串赋值
                String ref = getRefString(properties);
                //尝试下面的代码
                try {
                    //写入
                    outputStream.write(("<table><tr>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>名称</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>类型</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>格式</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>样例</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>说明</span></td>" +
                            " <td style='border-top:1px dash solid' ><span style='font-size:6'>引用见《所有对象的定义》</span></td>" +
                            // TODO
                            "</tr>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write(("<tr>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>&nbsp;</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( properties.get("type")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( properties.get("format")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( properties.get("example")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( properties.get("description")) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write((" <td style='border-top:1px dash solid' ><span style='font-size:6'>" + notNull( getRefString(properties)) + "</span></td>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write(("</tr>").getBytes(StandardCharsets.UTF_8));
                    //写入
                    outputStream.write(("</table>").getBytes(StandardCharsets.UTF_8));
                    //捕捉异常
                } catch (Exception e) {
                    //打印异常
                    e.printStackTrace();
                }
                //否则
            } else {
                //写文字
                writeText(outputStream, "" + CacheJsonUtil.toJson(schemaDefinitions), 6);
            }
        }
    }

    //拿引用字符串
    /**
     * 拿引用字符串
    */
    public static String getRefString(Map<String, Object> propertiesEntryValueMap) {
        //定义
        String ref;
        //判断
        if (null == propertiesEntryValueMap.get("items")) {
            //判断
            if (null == propertiesEntryValueMap.get("ref")) {
                //赋值
                ref = "";
                //否则
            } else {
                //赋值
                ref = "" + propertiesEntryValueMap.get("ref");
                //替换
                ref = ref.replaceAll("#/definitions/", "");
            }
            //否则
        } else {
            //拿出
            Map<String, Object> propertiesEntryValueMapRef = (Map) propertiesEntryValueMap.get("items");
            //赋值
            ref = "" + propertiesEntryValueMapRef.get("ref");
            //替换
            ref = ref.replaceAll("#/definitions/", "");
        }
        //返回
        return ref;
    }

    //写文字
    /**
     * 写文字
    */
    public static void writeText(OutputStream outputStream, String text, Integer fontsize) {
        //尝试下面的代码
        try {
            //写入
            outputStream.write(("<span style='font-size:" + fontsize + "'>" + text + "</span><br/><br/>").getBytes(StandardCharsets.UTF_8));
            //捕捉异常
        } catch (Exception e) {
            //打印异常
            e.printStackTrace();
        }
    }

    //写加粗文字
    /**
     * 写加粗文字
    */
    public static void writeBoldText(OutputStream outputStream, String text, Integer fontsize) {
        //尝试下面的代码
        try {
            //写入
            outputStream.write(("<span style='font-size:" + fontsize + ";font-weight:bold;'>" + text + "</span><br/><br/>").getBytes(StandardCharsets.UTF_8));
            //捕捉异常
        } catch (IOException e) {
            //打印异常
            e.printStackTrace();
        }
    }

    //返回非空字符串
    /**
     * 返回非空字符串
    */
    public static String notNull(Object s){
        //返回
        return s==null?"":s+"";
    }
}
